package ru.niir.goodfil.ui;

import org.apache.log4j.Logger;
import ru.niir.goodfil.db.Client;
import ru.niir.goodfil.db.DataExchange;
import ru.niir.goodfil.db.Order;
import ru.niir.goodfil.db.OrderItem;
import ru.niir.goodfil.db.dic.ExchangeState;
import ru.niir.goodfil.db.handlers.Goodfil;
import ru.niir.goodfil.exceptions.ConfigurationException;
import ru.niir.goodfil.exceptions.SettingNotFoundException;
import ru.niir.goodfil.exceptions.ValidationException;
import ru.niir.goodfil.utils.DateFormat;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import static ru.niir.goodfil.utils.Utils._assertNotNull;

/**
 * Бин для страницы Logs1C.jsp
 */
public class Logs1CBean extends PageBean {
    private static Logger logger = Logger.getLogger(Logs1CBean.class);

    public String getCurrentStateAsString() {
        logger.debug("getCurrentStateAsString() call");

        EnviromentControlBean enviromentControlBean = (EnviromentControlBean) getBean("EnviromentControlBean");
        if (enviromentControlBean == null) {
            logger.error("enviromentControlBean is null");
            return "Неизвестно";
        }

        if (enviromentControlBean.getC1Running()) {
            logger.debug("c1 is running");
            return "<span style=\"color:green;font-weight:bold\">Обмен запущен</span>";
        } else {
            logger.debug("c1 is stoped");
            return "<span style=\"color:red;font-weight:bold\">Обмен приостановлен</span>";
        }
    }

    public boolean getC1IsRunning() throws IOException, ParseException {
        return get1CIsRunning(gf());
    }

    public static boolean get1CIsRunning(Goodfil gf) throws IOException, ParseException {
        gf.createIfNotExists(".1c.directory", "/media/1c", "Путь к директории для обмена данными с 1С");
        String c1dir = gf.get(".1c.directory");

        if (c1dir == null) {
            throw new ConfigurationException("ОШИБКА: Не определена переменна .1c.directory");
        }

        File f = new File(c1dir + File.separator +
                "errors" + File.separator +
                "time.txt");
        if (!f.exists() || f.isDirectory()) {
            return false;
        }

        FileReader fr = new FileReader(f);
        BufferedReader br = new BufferedReader(fr);
        String time = br.readLine();
        br.close();
        fr.close();

        Date ts = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").parse(time);
        long l1 = ts.getTime(); // ms
        long l2 = Calendar.getInstance().getTimeInMillis(); // ms
        l1 = l1 / 1000; // s
        l2 = l2 / 1000; // s

        gf.createIfNotExists(".c1.dead.timeout", 60 * 2);
        int v = gf.getInt(".c1.dead.timeout");

        return l2 - l1 < v;
    }

    public String getLastExchangeDateAsString() {
        logger.debug("getLastExchangeDateAsString() call");

        gf().createIfNotExists(".1c.directory", "/media/1c", "Путь к директории для обмена данными с 1С");
        String c1dir = gf().get(".1c.directory");

        if (c1dir == null) {
            logger.error("c1dir is null");
            return "ОШИБКА: Не определена переменна .1c.directory";
        }

        File f = new File(c1dir + File.separator +
                "errors" + File.separator +
                "time.txt");
        if (!f.exists() || f.isDirectory()) {
            logger.error("time.txt not exists or is a directory (" + f.getPath() + ")");
            return "ОШИБКА: Отсутствует файл time.txt";
        }

        try {
            FileReader fr = new FileReader(f);
            BufferedReader br = new BufferedReader(fr);
            String time = br.readLine();
            br.close();
            fr.close();

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
            SimpleDateFormat sdf2 = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
            Date ts = sdf.parse(time);

            String s1 = "";
            String s2 = "";
            boolean v = false;
            try {
                v = get1CIsRunning(gf());
            } catch (Exception e) {
                s2 = " <span style=\"color:red;font-weight:normal;font-size:80%\">" + e.toString() + "</span>";
            }

            if (!v) {
                s1 = " <span style=\"color:red;font-weight:bold\"> (возможно, обмен со стороны 1С не запущен)</span>";
            }

            return sdf2.format(ts) + s1 + s2;
        } catch (IOException ioe) {
            ioe.printStackTrace();
            logger.error(ioe);
            return "ОШИБКА: ошибка чтения файла";
        } catch (ParseException pe) {
            pe.printStackTrace();
            logger.error(pe);
            return "ОШИБКА: неверный формат даты";
        }
    }

    public String getLastRestsImportDateAsString() {
        String s = gf().get(".1c.rests.last");
        logger.debug("getLastRestsImportDateAsString() call: " + s);

        if (s == null) {
            return "Неизвестно";
        } else {
            return s;
        }
    }

    public boolean getC1ErrorExists() {
        logger.debug("getC1ErrorExists() call");

        gf().createIfNotExists(".1c.directory", "/media/1c", "Путь к директории для обмена данными с 1С");
        String c1dir = gf().get(".1c.directory");

        if (c1dir == null) {
            logger.error("c1dir is null");
            return true;
        }

        File f = new File(c1dir + File.separator +
                "errors" + File.separator +
                "last_error.txt");
        logger.debug("Searching for " + f.getPath());

        logger.debug("File (" + f.getPath() + ") " + (f.exists() ? "exists" : "not exists"));
        return f.exists();
    }

    private List<StringPair> c1Error;

    public List<StringPair> getC1Error() {
        logger.debug("getC1Error() call");
        if (c1Error == null) {
            logger.debug("getC1Error() call init");
            c1Error = new ArrayList<StringPair>();

            gf().createIfNotExists(".1c.directory", "/media/1c", "Путь к директории для обмена данными с 1С");
            String c1dir = gf().get(".1c.directory");

            if (c1dir == null) {
                logger.error("c1dir is null");
                return new ArrayList<StringPair>();
            }

            File f = new File(c1dir + File.separator +
                    "errors" + File.separator +
                    "last_error.txt");
            logger.debug("Searching for " + f.getPath());
            if (!f.exists()) {
                logger.debug("File is not exists");
                return new ArrayList<StringPair>();
            }

            try {
                FileReader fr = new FileReader(f);
                BufferedReader br = new BufferedReader(fr);
                String errorName = br.readLine();

                try {
                    String line = br.readLine();
                    while (line != null) {
                        String[] arr = line.split("=");
                        String s1 = arr[0].trim();
                        String s2 = arr[1].trim();

                        // Заказ невозможно изменить из-за нехватки остатков.
                        // Строго говоря, такой ошибки не должно возникать, только если
                        // остатки не исправляются в 1С задним числом. Но она возникает
                        // время от времени.
                        if (errorName.equals("ORDER_CHANGE_ERROR_RESTS")) {
                            if (s1.equals("idIS")) {
                                c1Error.add(new StringPair("Код заказа в ИС", s2));
                            }
                            if (s1.equals("id1C")) {
                                c1Error.add(new StringPair("Код заказа в 1C", s2));
                            }
                            c1Error.add(new StringPair("Рекомендация", "Удалить ошибочный заказ из очереди на обмен и вручную сверить количество товара в 1С и в ИС (в 1С необходимо сделать как в ИС"));
                        }


                        // Не удалось изменить заказ, т.к. заказ с таким номером не найден в 1С.
                        if (errorName.equals("ORDER_CHANGE_ERROR_NO_ORDER")) {
                            if (s1.equals("idIS")) {
                                c1Error.add(new StringPair("Код заказа в ИС", s2));
                            }
                            if (s1.equals("id1C")) {
                                c1Error.add(new StringPair("Код заказа в 1C", s2));
                            }
                            c1Error.add(new StringPair("Рекомендация", "Вероятно, заказ корректировался на стороне 1С, что не допустимо. Необходимо удалить заказ из очереди на обмен и оформить его заново."));
                        }

                        if (errorName.equals("ERROR_CLIENT_BAD_MANAGER")) {
                            if (s1.equals("idIS")) {
                                c1Error.add(new StringPair("Код клиента в ИС", s2));
                            }
                            if (s1.equals("id1C")) {
                                c1Error.add(new StringPair("Код клиента в 1C", s2));
                            }
                            if (s1.equals("name")) {
                                c1Error.add(new StringPair("Наименование клиента", s2));
                            }
                            if (s1.equals("managerFIO")) {
                                c1Error.add(new StringPair("Менеджер (ОШИБОЧНЫЙ)", s2));
                            }
                        }
                        if (errorName.equals("ERROR_ORDER_BAD_CLIENT")) {
                            if (s1.equals("idIS")) {
                                c1Error.add(new StringPair("Код заказа в ИС", s2));
                            }
                            if (s1.equals("id1C")) {
                                c1Error.add(new StringPair("Код заказа в 1С", s2));
                            }
                            if (s1.equals("idClient1C")) {
                                c1Error.add(new StringPair("Код клиента в 1С (ОШИБОЧНЫЙ)", s2));
                            }
                            if (s1.equals("idClientIS")) {
                                c1Error.add(new StringPair("Код клиента в ИС", s2));
                            }
                        }
                        if (errorName.equals("ERROR_ORDER_BAD_GOOD")) {
                            if (s1.equals("idIS")) {
                                c1Error.add(new StringPair("Код заказа в ИС", s2));
                            }
                            if (s1.equals("id1C")) {
                                c1Error.add(new StringPair("Код заказа в 1С", s2));
                            }
                            if (s1.equals("goodCode1C")) {
                                c1Error.add(new StringPair("Код товара в 1С (ОШИБОЧНЫЙ)", s2));
                            }
                        }
                        if (errorName.equals("ERROR_ORDER_BAD_RESTS")) {
                            if (s1.equals("idIS")) {
                                c1Error.add(new StringPair("Код заказа в ИС", s2));
                            }
                            if (s1.equals("id1C")) {
                                c1Error.add(new StringPair("Код заказа в 1С", s2));
                            }
                            if (s1.equals("goodCode1C")) {
                                c1Error.add(new StringPair("Код товара в 1С", s2));
                            }
                            if (s1.equals("count")) {
                                c1Error.add(new StringPair("Количество (ОШИБОЧНОЕ)", s2));
                            }
                        }

                        line = br.readLine();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

                br.close();
                fr.close();

                if (errorName.equals("ORDER_CHANGE_ERROR_NO_ORDER")) {
                    errorName = "Не удалось изменить заказ, т.к. заказ с таким номером не найден в 1С";
                }
                if (errorName.equals("ORDER_CHANGE_ERROR_NO_ORDER")) {
                    errorName = "Заказ невозможно изменить из-за нехватки остатков";
                }
                if (errorName.equals("ERROR_CLIENT_BAD_MANAGER")) {
                    errorName = "Неверно указан менеджер в записи клиента";
                }
                if (errorName.equals("ERROR_ORDER_BAD_CLIENT")) {
                    errorName = "В записи заказа указан неверный клиент";
                }
                if (errorName.equals("ERROR_ORDER_BAD_GOOD")) {
                    errorName = "В записи заказа указан неверный товар";
                }
                if (errorName.equals("ERROR_ORDER_BAD_RESTS")) {
                    errorName = "Заказ невозможно провести из-за нехватки товара";
                }


                c1Error.add(new StringPair("Код ошибки", errorName));
            } catch (IOException ioe) {
                ioe.printStackTrace();
                logger.error(ioe);
                c1Error.add(new StringPair("ВНИМАНИЕ", "Невозможно прочесть файл с ошибкой"));
            }
        }
        return c1Error;
    }

    public List<LogItem> getLogs() throws SettingNotFoundException {
        List<LogItem> result = new ArrayList<LogItem>();
        List<DataExchange> des = gf().getTopDataExchanges();
        for (DataExchange de : des) {
            LogItem li = new LogItem();
            li.setNum(de.getId());

            if (de.getTableName().equals("Clients")) {
                Client c = gf().getClientById(de.getItemId());

                li.setType("Клиент");
                if (c != null) {
                    li.setItem(c.toClientString());
                } else {
                    li.setItem("---");
                }
            } else if (de.getTableName().equals("Orders")) {
                li.setType("Заказ");
                Order o = gf().getOrderById(de.getItemId());
                if (o == null) {
                    li.setItem("Заказ отсутствует в БД");
                } else if (o.isDeleted()) {
                    li.setItem("Удаление заказа #" + de.getItemId());
                } else {
                    gf().countOrderDeliverySum(o);
                    gf().countOrderSum(o);

                    Client c = gf().getClientById(o.getClientId());
                    li.setItem(o.toClientString(c));
                }
            } else if (de.getTableName().equals("OrderBuild")) {
                li.setType("Изм. заказа");
                Order o = gf().getOrderById(de.getItemId());
                if (o == null) {
                    li.setItem("Заказ отсутствует в БД");
                } else if (o.isDeleted()) {
                    li.setItem("Удаление заказа #" + de.getItemId());
                } else {
                    gf().countOrderDeliverySum(o);
                    gf().countOrderSum(o);

                    Client c = gf().getClientById(o.getClientId());


                    // Выясняем, выгружался ли заказ в 1С с измененными остатками,
                    // либо же он выгружался просто для фиксации факта сборки.
                    Boolean orderWasChanged = null;
                    try {
                        List<OrderItem> orderItems = gf().getOrderItemsByOrderId(o.getId());
                        for (OrderItem orderItem : orderItems) {
                            int count = orderItem.getCount();
                            int factGiven = orderItem.getFactGivenFromStore();

                            if (factGiven > 0 && count != factGiven) {
                                orderWasChanged = true;
                            }
                        }
                    } catch (Exception e) {
                        logger.error(e);
                    }

                    String item = o.toClientString(c);
                    if (orderWasChanged != null && orderWasChanged.booleanValue()) {
                        item += "[ ЗАКАЗ БЫЛ ИЗМЕНЕН ]";
                    } else {
                        item += "[ без изменений ]";
                    }

                    li.setItem(item);
                }
            }
            else if(de.getTableName().equals("OrderPrint")){
                li.setType("Запрос счета");
                StringBuilder itemString = new StringBuilder();
                itemString.append("Запрос счета из 1С на заказ номер ");
                itemString.append(de.getItemId());
                li.setItem(itemString.toString());
            }
            else  if(de.getTableName().equals("Rests")){
                li.setType("Выгрузка остатков");
                li.setItem("Выгрузка остатков " + DateFormat.FormatDateAndTime(de.getCreationDate()));
            }
            else {
                li.setType("<i>???</i>");
                li.setItem("<i>???</i>");
            }

            if (de.getExchangeStateId() == ExchangeState.QUEUED) {
                li.setState("<span style=\"font-weight:bold;color:dimgray\">В очереди</span>");
            } else if (de.getExchangeStateId() == ExchangeState.SENT) {
                li.setState("<span style=\"font-weight:bold;color:darkred\">Отправлено</span>");
            } else if (de.getExchangeStateId() == ExchangeState.ACCEPTED) {
                li.setState("<span style=\"font-weight:bold;color:darkgreen\">Принято</span>");
            } else {
                li.setState("???");
            }

            li.setTimestamp(de.getCreationDate());

            result.add(li);
        }
        return result;
    }

    /**
     * Перезапустить обмен с 1С. Для этого нужно: - удалить последнюю выгрузку - удалить сообщение об ошибке - поставить
     * у последней выгрузки статус в очереди - перезапустить обмен
     */
    public void
    restart() {

        /** Этот метод надолго сваливал обмен так как заставлял всплывать старые непрошедшие заказы в очереди
         *
        logger.debug("Restarting 1C integration...");

        gf().createIfNotExists(".1c.directory", "/media/1c", "Путь к директории для обмена данными с 1С");
        String c1dir = gf().get(".1c.directory");
        _assertNotNull(c1dir);

        //  Удаляем все выгрузки
        logger.debug("Removing output xml");
        File dir = new File(c1dir);
        File[] fs = dir.listFiles();
        for (File f : fs) {
            if (f.getName().startsWith("fromISto1C") && f.getName().endsWith(".xml")) {
                f.delete();
            }
        }

        //  Удалили файл с ошибкой
        logger.debug("Removing last_error.txt");
        File last_error = new File(c1dir + File.separator +
                "errors" + File.separator +
                "last_error.txt");
        last_error.delete();

        //  Обновили запись
        logger.debug("Updating last data exchange");
        List<DataExchange> des = gf().getErrorDataExchanges();
        for (DataExchange de : des) {
            gf().updateDataExchangeState(de.getId(), ExchangeState.QUEUED);
        }

        //  Перезапускаем обмен
        try {
            logger.debug("Restarting 1C integration");
            EnviromentControlBean enviromentControlBean = (EnviromentControlBean) getBean("EnviromentControlBean");
            enviromentControlBean.startC1();
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
         */
    }

    //
    //  Удаление DataExchange --------------------------------------------------------------------------------------------------------
    //

    private long removeId;

    public long getRemoveId() {
        return removeId;
    }

    public void setRemoveId(long removeId) {
        this.removeId = removeId;
    }

    public void removeDataExchange() {
        gf().removeDataExchange(removeId);
    }

    //  ------------------------------------------------------------------------------------------------------------------------------

    public static class LogItem {
        private long num;

        private String type;

        private String item;

        private String state;

        private Timestamp timestamp;

        public long getNum() {
            return num;
        }

        public void setNum(long num) {
            this.num = num;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getItem() {
            return item;
        }

        public void setItem(String item) {
            this.item = item;
        }

        public String getState() {
            return state;
        }

        public void setState(String state) {
            this.state = state;
        }

        public Timestamp getTimestamp() {
            return timestamp;
        }

        public void setTimestamp(Timestamp timestamp) {
            this.timestamp = timestamp;
        }
    }

    public static class StringPair {
        private String s1;

        private String s2;

        public StringPair() {
        }

        public StringPair(String s1, String s2) {
            this.s1 = s1;
            this.s2 = s2;
        }

        public String getS1() {
            return s1;
        }

        public void setS1(String s1) {
            this.s1 = s1;
        }

        public String getS2() {
            return s2;
        }

        public void setS2(String s2) {
            this.s2 = s2;
        }
    }
}
